package io.chenglicun.common.trans.core;

import cn.hutool.core.annotation.AnnotationUtil;
import io.chenglicun.common.trans.annotation.Trans;
import io.chenglicun.common.trans.service.impl.TransRepository;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 需要翻译的类源信息
 */
@Slf4j
public class TransClassMeta implements Serializable {

    private static final long serialVersionUID = -8211850528694193388L;

    private final Class<?> clazz;

    /**
     * 获取翻译字段 key 翻译的类型比如字典的类型为dict
     */
    private final Map<Class<? extends TransRepository>, List<TransField>> transFieldMap = new ConcurrentHashMap<>();

    /**
     * 获取翻译字段 key 翻译的类型比如字典的类型为dict
     */
    private final Map<Class<? extends TransRepository>, List<TransField>> dependTransFieldMap = new ConcurrentHashMap<>();

    private volatile boolean canTrans = false;

    public TransClassMeta(Class<?> clazz) {
        super();
        this.clazz = clazz;
        getClazzFieldMap();
    }

    /**
     * 获取需要翻译的字段
     *
     * @param clazz 翻译类型
     * @return 字段集合
     */
    public List<TransField> getDependTransField(Class<? extends TransRepository> clazz) {
        return new ArrayList<>(dependTransFieldMap.getOrDefault(clazz, new ArrayList<>()));
    }

    /**
     * 获取需要翻译的字段
     *
     * @param clazz 翻译类型
     * @return 字段集合
     */
    public List<TransField> getTransField(Class<? extends TransRepository> clazz) {
        return new ArrayList<>(transFieldMap.getOrDefault(clazz, new ArrayList<>()));
    }

    private void getClazzFieldMap() {
        List<Field> declaredFields = getAllField(clazz);
        int mod;
        // 循环遍历所有的属性进行判断
        for (Field field : declaredFields) {
            mod = field.getModifiers();
            // 如果是 static, final, volatile, transient 的字段，则直接跳过
            if (Modifier.isStatic(mod) || Modifier.isFinal(mod) || Modifier.isVolatile(mod)) {
                continue;
            }

            Trans trans = AnnotationUtil.getAnnotation(field, Trans.class);
            if (trans != null) {
                Class<? extends TransRepository> repositoryClass = trans.using();
                if (repositoryClass == null) {
                    log.warn("类 {} 属性 [{}] 未配置查询仓库！", clazz.getName(), field.getName());
                } else {
                    boolean depend = trans.depend();
                    List<TransField> fieldList;
                    if (depend) {
                        fieldList = dependTransFieldMap.computeIfAbsent(repositoryClass, k -> new ArrayList<>());
                    } else {
                        fieldList = transFieldMap.computeIfAbsent(repositoryClass, k -> new ArrayList<>());
                    }
                    fieldList.add(new TransField(trans, field));
                    canTrans = true;
                }
            }
        }
    }

    public boolean needTrans() {
        return this.canTrans;
    }

    /**
     * 获取一个class的所有的字段
     */
    private static List<Field> getAllField(Class<?> clazz) {
        Field[] fields;
        List<Field> result = new ArrayList<>();
        for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                fields = clazz.getDeclaredFields();
                result.addAll(Arrays.asList(fields));
            } catch (Exception e) {
                // 这里甚么都不要做！并且这里的异常必须这样写，不能抛出去。
                // 如果这里的异常打印或者往外抛，则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
            }
        }
        return result;
    }

}
